package com.zlyx.easy.core.reflect;

import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;

import com.zlyx.easy.core.utils.ClassUtils;
import com.zlyx.easy.core.utils.FileUtils;
import com.zlyx.easy.core.utils.StringUtils;

/**
 * <p>
 * 类文件内容
 * </p>
 *
 * @author 赵光
 * @since 2020年6月10日
 */
public class ClassBody {

	public static String CLASSBODY = "package ${PACKAGENAME};\n\n${HEADER}public class ${CLASSNAME} {\n ${BODY}\n}";

	public static String METHODBODY = "\n  ${NOTE}\n  public void  ${NANE}(${PARAMTERS}) throws Exception {\n    ${BODY}\n  }\n";

	/**
	 * 包路径
	 */
	protected String packageName;

	/**
	 * 导入包
	 */
	protected Set<String> importClass;

	/**
	 * 文件头(导入包 + 类注释)
	 */
	protected String header;

	/**
	 * 类名
	 */
	protected String className;

	/**
	 * 方法名
	 */
	protected Map<String, String> fields;

	/**
	 * 方法名
	 */
	protected Map<String, String> methods;

	/**
	 * 属性
	 */
	protected Map<String, String> props;

	public ClassBody() {
		this.methods = new TreeMap<>();
		this.fields = new TreeMap<>();
		this.importClass = new HashSet<>();
	}

	public ClassBody(String packageName, String className, Collection<Class<?>> importClass) {
		this();
		this.packageName = packageName;
		this.className = className;
		this.importClass(importClass);
	}

	/**
	 * 设置包名
	 *
	 * @param packageName
	 * @return
	 */
	public ClassBody packageName(String packageName) {
		this.packageName = packageName;
		return this;
	}

	/**
	 * 返回包名
	 *
	 * @return
	 */
	public String getPackageName() {
		return packageName;
	}

	/**
	 * @param importClass
	 * @return
	 */
	public ClassBody importClass(String... importClass) {
		this.importClass.addAll(Arrays.asList(importClass));
		return this;
	}

	/**
	 * 设置导入类
	 *
	 * @param importClass
	 * @return
	 */
	public ClassBody importClass(Class<?>... importClass) {
		importClass(Arrays.asList(importClass));
		return this;
	}

	/**
	 * 设置导入类
	 *
	 * @param importClass
	 * @return
	 */
	public ClassBody importClass(Collection<Class<?>> importClass) {
		if (importClass != null && !importClass.isEmpty()) {
			for (Class<?> cls : importClass) {
				this.importClass.add(cls.getName());
			}
		}
		return this;
	}

	/**
	 * 类名
	 *
	 * @return
	 */
	public Set<String> getImportClass() {
		return this.importClass;
	}

	/**
	 * 文件头
	 *
	 * @param header
	 * @return
	 */
	public ClassBody header(String header) {
		if (StringUtils.isNotBlank(header)) {
			this.header = header;
		}
		return this;
	}

	/**
	 * 文件头
	 *
	 * @return
	 */
	public String header() {
		return header;
	}

	/**
	 * 设置类名
	 *
	 * @param className
	 * @return
	 */
	public ClassBody className(String className) {
		this.className = className;
		return this;
	}

	/**
	 * 返回类名
	 *
	 * @return
	 */
	public String getClassName() {
		return className;
	}

	/**
	 * 设置字段
	 *
	 * @param field
	 * @return
	 */
	public ClassBody field(String name, String field) {
		this.fields.put(name, field);
		return this;
	}

	/**
	 * 返回字段
	 *
	 * @return
	 */
	public Map<String, String> getFields() {
		return fields;
	}

	/**
	 * 添加方法
	 *
	 * @param name
	 * @param method
	 * @return
	 */
	public ClassBody method(String name, String method) {
		this.methods.put(name, method);
		return this;
	}

	/**
	 * 添加含参方法体
	 *
	 * @param name           方法名
	 * @param paramterString 方法参数
	 * @param body           方法体
	 * @return
	 * @throws Exception
	 */
	public ClassBody method(String name, String paramterString, String body) throws Exception {
		String[] paramtersArray = StringUtils.split(paramterString, ",");
		String methodNote = "/**\n   * " + name + "\n   *";
		if (paramtersArray != null) {
			for (String paramter : paramtersArray) {
				String[] paramterArray = StringUtils.split(paramter, " ");
				if (paramterArray != null) {
					methodNote += "\n   *  @param " + paramterArray[1] + " " + paramterArray[1];
				}
			}
		}
		methodNote += "\n   *\n   * @throws Exception\n   */";
		return method(name, methodNote, paramterString, body);
	}

	/**
	 * 添加方法并导入类
	 *
	 * @param name
	 * @param paramters
	 * @param methodBody
	 * @throws Exception
	 */
	public ClassBody method(String name, Map<Class<?>, String> paramters, String methodBody) throws Exception {
		importClass(paramters.keySet());
		String methodNote = "/**\n   * " + name + "\n   *";
		String paramterString = "";
		String paramterName = null;
		if (!paramters.isEmpty()) {
			for (Entry<Class<?>, String> entry : paramters.entrySet()) {
				paramterName = entry.getKey().getSimpleName();
				paramterString += ", " + paramterName + " " + entry.getValue();
				methodNote += "\n   * @param " + entry.getValue() + " " + entry.getValue();
			}
			paramterString = paramterString.substring(2);
			methodNote += "\n   *\n   * @throws Exception\n   */";
		}
		return method(name, methodNote, paramterString.toString(), methodBody);
	}

	/**
	 * @return
	 */
	public String getMethod(String name) {
		return methods.get(name);
	}

	/**
	 * @return
	 */
	public Map<String, String> getMethods() {
		return methods;
	}

	/**
	 * 添加含参方法体
	 *
	 * @param name           方法名
	 * @param note           注释
	 * @param paramterString 方法参数
	 * @param body           方法体
	 * @return
	 * @throws Exception
	 */
	private ClassBody method(String name, String note, String paramterString, String body) throws Exception {
		return method(name, METHODBODY.replace("${NOTE}", note).replace("${NANE}", name)
				.replace("${PARAMTERS}", paramterString).replace("${BODY}", body));
	}

	/**
	 * 执行构建
	 *
	 * @return
	 */
	public String build() {
		if (header == null) {
			header = "";
		}
		String importString = "";
		if (!importClass.isEmpty()) {
			for (String clsName : importClass) {
				if (!header.contains(clsName) && clsName.contains(".") && !clsName.contains("java.lang")) {
					if (clsName.contains("import")) {
						importString += clsName;
					} else {
						importString += "import " + clsName + ";\n";
					}
				}
			}
		}
		StringBuilder classBody = new StringBuilder();
		for (Entry<String, String> field : fields.entrySet()) {
			classBody.append(field.getValue()).append("\n");
		}
		for (Entry<String, String> method : methods.entrySet()) {
			classBody.append(method.getValue()).append("\n");
		}
		Map<String, String> props = new HashMap<>();
		props.put("${PACKAGENAME}", packageName);
		props.put("${HEADER}", importString + header);
		props.put("${CLASSNAME}", className);
		props.put("${BODY}", classBody.toString());
		return StringUtils.replaceAll(CLASSBODY, props);
	}

	/**
	 * 写出为java文件
	 *
	 * @return
	 * @throws Exception
	 */
	public String writeAsFile() throws Exception {
		return writeAsFile(false);
	}

	/**
	 * 写出为文件
	 *
	 * @param rewrite 是否强制重写文件
	 * @throws Exception
	 */
	public String writeAsFile(boolean rewrite) throws Exception {
		String path = ClassUtils.getPath() + "\\src\\main\\java\\" + packageName.replace(".", "\\");
		String fileName = className + ".java";
		return FileUtils.writeAsFile(path, fileName, build(), rewrite);
	}

	/**
	 * 写出为文件
	 *
	 * @param filePath 文件路径
	 * @param rewrite  是否强制重写文件
	 * @throws Exception
	 */
	public String writeAsFile(String filePath, boolean rewrite) throws Exception {
		return FileUtils.writeAsFile(filePath + packageName.replace(".", "\\"), className + ".java", build(), rewrite);
	}

	@Override
	public String toString() {
		return build();
	}

}
